#coding:utf-8

'''
event loop class or method
'''

import time
from logging import getLogger
import bisect

from Queue import Queue, Empty

from event import (EvtFinished, DelayEvent, EmptyEvent)
import sys


PRIORITY_HIGHIEST, PRIORITY_HIGHER, PRIORITY_NOMAL, PRIORITY_LOW, \
PRIORITY_LOWEST = range(1, 6)


class EventLoop(object):

    def __init__(self):
        self._evt_queue = Queue()
        # self._evt_queue = PriorityQueue()
        self._pending_evts = []
        self._pending_dlyevts = []
        self.logger = getLogger('mevent.loop')
        # counter for events processed by me
        self._cnt_evt = 0

        # self.postEvent(IdleEvent())

    def postInstanceEvent(self, e, priority = PRIORITY_NOMAL):
        self._evt_queue.put(e)

    def postEvent(self, event):
        if isinstance(event, DelayEvent):
            bisect.insort(self._pending_dlyevts, event)
        else:
            self._pending_evts.append(event)
        # self._evt_queue.put((priority, event))

    def hasEvent(self):
        if self._evt_queue.qsize() > 0:
            return True
        return False

    def getEvent(self):
        try:
            evt = self._evt_queue.get(True, 1)
            # unused_num, evt = self._evt_queue.get(True, 1)
            return evt
        except Empty:
            return EmptyEvent()

    def loop(self):
        count = 0
        while True:
            while self.hasEvent():
                self.processEvent()

            self.processPendingEvent()
            count += 1
            if count == 1000:
                self.logger.debug("%d events processed", self._cnt_evt)
                count = 0
                #sys.exit()
            ## idle the cpu time
            time.sleep(0.01)

    def processPendingEvent(self):

        for e in self._pending_dlyevts:
            if e.isReady():
                self.postInstanceEvent(e)
                self._pending_dlyevts.remove(e)
            else:
                break

        for e in self._pending_evts:
            if e.isReady():
                self.postInstanceEvent(e)
                self._pending_evts.remove(e)

    def processEvent(self):
        e = self.getEvent()
        self._cnt_evt += 1
        if not e.isReady():
            self.postEvent(e)
            return

        try:
            e.callBack()
        except EvtFinished:
            return
        except Exception:
            import traceback
            self.logger.error(traceback.format_exc())
        else:
            # self.logger.debug("post event back")
            if e.isRepeat():
                self.postEvent(e)
